Skip to content

Report full data path in incompatible-update invariant messages#689

Draft
vladar wants to merge 2 commits into
mainfrom
vladar/fix-update-object-error-path
Draft

Report full data path in incompatible-update invariant messages#689
vladar wants to merge 2 commits into
mainfrom
vladar/fix-update-object-error-path

Conversation

@vladar

@vladar vladar commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Why

Incompatible-update invariants surfaced in telemetry with truncated paths, e.g.:

Failed to update "query ...AppDefinitionsQuery" at path meetingExtensionDefinition: expected CompositeNull, got ObjectDifference

But meetingExtensionDefinition is not a root field of that operation; it is nested several levels deep. The reported path was just the last segment, which makes these errors much harder to diagnose.

Root cause

When the failing value is a CompositeNull / CompositeUndefined, its source data is null / undefined, so getDataPathForDebugging cannot locate it in the tree. The message builder then fell back to describeLocation, which only knew the immediate field/index, dropping the rest of the path.

Approach

Thread the failing value's parent chunk (always an addressable ObjectChunk/CompositeListChunk) into the update location, and derive the path from the parent plus the field/index step. This yields the full path (e.g. listContainer.items.0.value) even when the failing value itself is not addressable. The enclosing (in <TypeName>) node clause is likewise resolved from the parent when the value itself can't anchor it.

Failing gracefully

These builders run while the cache is already in an inconsistent state, so they must never throw over the invariant they are reporting. Every path/type helper is wrapped in try/catch. Because this change moved path derivation from an eagerly-captured primitive to a nested property access (location.field.dataKey), resolveFailurePath is now wrapped as well, matching the existing defensive style. If resolution throws, the message drops the path/node clause and still surfaces the invariant.

Tests

  • Full path is reported when the failing value is a nested CompositeNull.
  • Message builder degrades gracefully and still surfaces the invariant when findParent throws during both path and enclosing-node resolution.

The tests use a synthetic query; the private operation from telemetry is not referenced.

vrazuvaev and others added 2 commits July 10, 2026 18:22
When an incompatible-update invariant fires on a non-addressable value (a CompositeNull/CompositeUndefined, whose source data is null/undefined), getDataPathForDebugging cannot locate it, so the message fell back to only the last field/index segment (e.g. 'value' instead of 'listContainer.items.0.value').

Thread the failing value's parent chunk (always an addressable ObjectChunk/CompositeListChunk) into the location and derive the path from the parent plus the field/index step, so the full path is reported even for non-addressable values. The enclosing (in <TypeName>) node is likewise resolved from the parent when needed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ution

resolveFailurePath now derives the path from a nested property (location.field.dataKey) rather than an eagerly-captured primitive, so a malformed field could throw while building the invariant message and mask the real invariant. Wrap the whole derivation in try/catch, consistent with the other best-effort diagnostic helpers (chunkPath, nodeTypeClause), so path resolution can never throw over the invariant it is reporting.

Add a regression test that forces findParent to throw during both path and enclosing-node resolution and asserts the invariant message still surfaces.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

📊 Benchmark Analysis Report

No significant performance changes detected


Threshold: 5% change


Updated: 2026-07-10T16:49:14.900Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant